「有那麼一段時間我過著像公子哥一樣的生活,在歐洲的大城市到處打轉:巴黎、威尼斯、羅馬,終日忙著收集寶石,打獵,用
dispatch
發送事件,然後試著忘記那些發生在我身上的傷心往事。」~節錄自《The Great Svelte:第四章》
昨天我們討論到如何在 Svelte 的專案裡頭,將子元件 (child component) 的 HTML 元素的事件直接往上傳達給父元件 (parent component),不作任何包裝,而是在父元件 (parent component) 當中透過 event.target
來追本溯源,判斷究竟事件是來自於哪一個 HTML 元素,接著才做出相對應的動作。
反過來說,其實還有另一種做法。也就是先在子元件 (child component) 當中將事件透過事件處理器描述清楚,再向上傳遞到父元件 (parent)。這麼一來,父元件就不需要做太過複雜的邏輯設計去抽絲剝繭究竟發生什麼事件。這兩種策略沒有孰優孰劣,就看使用的場合。而我們能掌握的技術當然是越多越好,所以今天就來看看怎麼在 Svelte 做出屬於自己的事件。
在 Svelte 當中,我們可以透過 on:eventname
並省略事件處理器,將發生的事件從子元件 (child component) 傳遞出去。然而這樣一來,所有的事件相關的處裡邏輯都需要在外部的父元件 (parent component) 來進行,有一種隔靴搔癢的感覺。能不能先在子元件 (child component) 中添加事件處理器,先做一些邏輯運算,將事件定義得更清楚,然後再往上傳遞給父元件 (parent component),使其可以更輕鬆地接收呢?
答案當然是肯定的。那麼要怎麼做呢?其實只要學會如何在 Svelte 當中做出客製化的事件就可以了。
在 Svelte 當中做出客製化事件,需要在 Javascript 的段落當中寫三行程式碼:
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
dispatch('eventName', eventDetail);
第一行:import { createEventDispatcher } from "svelte";
從 Svelte 當中引入 createEventDispatcher
。
第二行:const dispatch = createEventDispatcher();
初始化一個事件發送器。
第三行:dispatch('eventName', eventDetail);
向外部的元件發送我們的客製化事件。第一個參數 eventName
是代表事件的名稱,可以使用任何字串做為事件的名稱。而第二個參數 eventDetail
則可以用來描述事件的細節,可以放入任何類型的資料。
就是這三行,沒有更多了。那麼讓我們實際來應用在專案當中試試看吧。
先到 Counter.svelte
把客製化的事件做出來:
/src/lib/Counter.svelte
<script>
import { createEventDispatcher } from "svelte";
export let count = 100;
const dispatch = createEventDispatcher();
const handleClick = (delta) => {
dispatch('changeCount', delta);
}
</script>
<section>
<h1>Create Color Palette for Me!</h1>
<div class='counter'>
<button on:click={() => handleClick(-1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewer">
<p>{count}</p>
</div>
<button on:click={() => handleClick(1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
</section>
第二行:import { createEventDispatcher } from "svelte";
如同先前介紹的,要從 Svelte 模組引入 createEventDispatcher
。
第六行:const dispatch = createEventDispatcher();
同樣的,初始化一個事件產生器 dispatch
。
第八行:const handleClick = (delta) => {
宣告一個函式 handleClick
,用來處理 <button>
的 click
事件。這個函式可以接收一個參數 delta
。我們接著會在第十七行跟第二十五行看到 delta
就是用來表達「加一」、「減一」的參數。
第九行:dispatch('changeCount', delta);
用 dispatch
這個 Svelte 提供的函式將我們客製化的事件傳遞出去。事件的名稱是 changeCount
,到底是「加一」還是「減一」,關於事件的詳細情況,則是作為函式的第二個參數跟著一起傳遞出去了。
第十七行:<button on:click={() => handleClick(-1)}>
利用 handleClick(-1)
做出一個按下去就會傳遞出「減一」這個消息的 <button>
。
第二十五行:<button on:click={() => handleClick(1)}>
利用 handleClick(1)
做出一個按下去就會傳遞出「加一」這個消息的 <button>
。
接著修改 App.svelte
:
/src/App.svelte
<!-- 在 Javascript 當中 import Counter -->
<script>
import Counter from './lib/Counter.svelte';
let count = 100;
let someState = 'TheGreatSvelte';
const sparkle = (text) => {
const sparkles = ['★', '☆', '✧', '✪'];
const randomSparkles = () => sparkles[Math.floor(Math.random() * sparkles.length)];
const sparkledText = text.split('').reduce((a, c) => a + randomSparkles() + c, '');
return sparkledText;
}
const href = 'https://ithelp.ithome.com.tw/users/20120178/ironman/7031';
const handleClick = (e) => {
console.log(e);
}
</script>
<main>
<!-- 在 HTML 當中直接嵌入 Counter -->
<Counter {count} on:changeCount={handleClick}/>
<p class='comment'>Check out <a {href}>Svelte Tutorial</a>, the awesome article powered by {sparkle(someState)}!</p>
</main>
第三行:import Counter from './lib/Counter.svelte';
引入 Counter
。
第五行:let count = 100;
宣告變數 count
。
第十七行:const handleClick = (e) => {
宣告一個作為事件處理器的函式 handleClick
,這個函式會接收一個事件作為參數。
第十八行:console.log(e);
將接收到的事件記錄下來。
第二十四行:<Counter {count} on:changeCount={handleClick}/>
利用 on:changeCount
接收來自 <Counter />
的 changeCount
事件,並用 handleClick
這個函式做為 changeCount
的事件處理器。
圖一、看看我們那精美的客製化事件 changeCount
仔細檢查我們的客製化事件 changeCount
所記錄下來的事件物件,可以看到兩個比較重要的資訊,第一個是 type
為 changeCount
,重新確認我們沒有亂接事件。第二個則是 detail
,這個則是我們利用 dispatch
放入的第二個參數。
那麼現在應該不難想像該如何利用這個客製化事件來讓 count
動起來了。
重新修改一下 App.svelte
:
/src/App.svelte
<!-- 在 Javascript 當中 import Counter -->
<script>
import Counter from './lib/Counter.svelte';
let count = 100;
let someState = 'TheGreatSvelte';
const sparkle = (text) => {
const sparkles = ['★', '☆', '✧', '✪'];
const randomSparkles = () => sparkles[Math.floor(Math.random() * sparkles.length)];
const sparkledText = text.split('').reduce((a, c) => a + randomSparkles() + c, '');
return sparkledText;
}
const href = 'https://ithelp.ithome.com.tw/users/20120178/ironman/7031';
const handleClick = (e) => {
console.log(e);
count += e.detail;
}
</script>
<main>
<!-- 在 HTML 當中直接嵌入 Counter -->
<Counter {count} on:changeCount={handleClick}/>
<p class='comment'>Check out <a {href}>Svelte Tutorial</a>, the awesome article powered by {sparkle(someState)}!</p>
</main>
count += e.detail;
e.detail
讀出到底是要「加一」還是「減一」。接著讓 count
重新賦值成 count + e.detail
就完成囉!
圖二、又又可以加加減減了
這就是 Svelte 提供的客製化事件,是不是很方便呢?那麼今天的內容就到這邊了,謝謝大家。